package com.zyh.scs.admin.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zyh.scs.admin.api.constant.RechargeChannelEnum;
import com.zyh.scs.admin.api.constant.RechargeTypeEnum;
import com.zyh.scs.admin.api.constant.UserStateEnum;
import com.zyh.scs.admin.api.dto.RechargeBatchDTO;
import com.zyh.scs.admin.api.dto.RechargeBatchJsonDTO;
import com.zyh.scs.admin.api.dto.RechargePageDTO;
import com.zyh.scs.admin.api.dto.RechargePhoneDTO;
import com.zyh.scs.admin.api.dto.open.RechargeBatchExcelVO;
import com.zyh.scs.admin.api.entity.*;
import com.zyh.scs.admin.api.utils.JsonToListUtil;
import com.zyh.scs.admin.api.utils.UserTypeToNameUtil;
import com.zyh.scs.admin.api.vo.ReadExcelVO;
import com.zyh.scs.admin.api.vo.UserHistoryExcelVO;
import com.zyh.scs.admin.api.vo.UserRechargeBatchFailVO;
import com.zyh.scs.admin.api.vo.UserRechargeBatchSuccessVO;
import com.zyh.scs.admin.mapper.*;
import com.zyh.scs.admin.service.UserRechargeRecordService;
import com.zyh.scs.admin.service.UserRechargeService;
import com.zyh.scs.admin.service.UserTransactionService;
import com.zyh.scs.common.core.exception.OpenException;
import com.zyh.scs.common.core.exception.OpenResponseCode;
import com.zyh.scs.common.core.util.MinioUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.jetbrains.annotations.NotNull;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author hwh
 * @ClassName: 用户充值实现类$
 * @Description: $
 * @Date $
 * @Version 1.0
 */
@Slf4j
@Service
@AllArgsConstructor
public class UserRechargeServiceImpl extends ServiceImpl<UserRechargeMapper, UserRecharge> implements UserRechargeService {

    private final SysUserMapper sysUserMapper;

    private final UserRechargeRecordMapper userRechargeRecordMapper;

    private final UserRechargeRecordService userRechargeRecordService;

    private final UserTransactionService userTransactionService;

    private final MinioUtil minioUtil;

    private final UserHistoryRechargeMapper userHistoryRechargeMapper;

    private final UserTransactionMapper userTransactionMapper;

    private final UserDictMapper userDictMapper;

    private final RedissonClient redissonClient;

    private final String XLSX = ".xlsx";

    @Override
    public IPage getUserPage(Page page) {
        Page<UserRecharge> userRechargePage = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<UserRecharge> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(UserRecharge::getCreateTime, UserRecharge::getRechargeId);
        return this.page(userRechargePage, queryWrapper);
    }

    @Override
    public List<SysUser> getRechargePhone(String param) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                //工号
                .eq(SysUser::getUserJobNumber, param)
                .or()
                //guid
                .eq(SysUser::getGuid, param)
                .or()
                //手机号
                .eq(SysUser::getPhone, param);
        //兼容模式
        //手机号 工号 guid userId
        queryWrapper.eq(SysUser::getDelFlag, 0)
                .orderByDesc(SysUser::getCreateTime);
        return sysUserMapper.selectList(queryWrapper);
    }

    @Override
    public Boolean recharge(RechargePhoneDTO rechargePhoneDTO) {
        SysUser validUser = sysUserMapper.selectByGuid(rechargePhoneDTO.getGuid());
        if (validUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            //冻结的充值失败
            throw new OpenException(OpenResponseCode.UNABLE_TO_RECHARGE);
        }
        if (rechargePhoneDTO.getRechargeType().equals("1")) {
            if (validUser.getCardState().equals("2")) {
                throw new OpenException(OpenResponseCode.UNABLE_TO_RECHARGE);
            }
        }
        if (rechargePhoneDTO.getRechargeType().equals("2")) {
            if (validUser.getCashState().equals("2")) {
                throw new OpenException(OpenResponseCode.UNABLE_TO_RECHARGE);
            }
        }
        //判断2分钟内是否重复充值
        UserRechargeRecord userRechargeRecord = userRechargeRecordMapper.selectOne(Wrappers.<UserRechargeRecord>lambdaQuery().eq(ObjectUtils.isNotEmpty(rechargePhoneDTO.getGuid()), UserRechargeRecord::getGuid, rechargePhoneDTO.getGuid()).eq(UserRechargeRecord::getRechargeType, rechargePhoneDTO.getRechargeType()).orderByDesc(UserRechargeRecord::getCreateTime).last("limit 1"));

        if (userRechargeRecord != null) {
            if (userRechargeRecord.getLastRechargeTime() != null) {
                //有充值记录 判断是否重复充值
                if (LocalDateTime.now().isBefore(userRechargeRecord.getLastRechargeTime().plusMinutes(2)) && userRechargeRecord.getRechargeNumber().compareTo(rechargePhoneDTO.getRechargeNumber()) == 0) {
                    throw new OpenException(OpenResponseCode.REPEATED_RECHARGE);
                }
            }
        }
        if (rechargePhoneDTO.getRechargeType().equals("1")) {
            sysUserMapper.incrByCardAccount(validUser.getGuid(), rechargePhoneDTO.getRechargeNumber(), LocalDateTime.now());
        } else {
            sysUserMapper.incrByCashAccount(validUser.getGuid(), rechargePhoneDTO.getRechargeNumber(), LocalDateTime.now());
        }
        //保存充值记录
        String rechargeStream = UserTypeToNameUtil.setRechargeStream();
        UserRechargeRecord userRecordInsert = new UserRechargeRecord();
        BeanUtil.copyProperties(rechargePhoneDTO, userRecordInsert);
        SysUser user = sysUserMapper.selectById(validUser.getUserId());
        userRecordInsert.setCreateBy(user.getUsername());
        userRecordInsert.setCreateTime(LocalDateTime.now());
        userRecordInsert.setLastRechargeTime(LocalDateTime.now());
        userRecordInsert.setRechargeStream(rechargeStream);
        userRecordInsert.setUserType(user.getUserType());
        userRecordInsert.setUsername(user.getUsername());
        userRecordInsert.setRechargeChannel(RechargeChannelEnum.BACK_GROUND.getCode());
        userRecordInsert.setCashAccount(user.getCashAccount());
        userRecordInsert.setCardAccount(user.getCardAccount());
        userRecordInsert.setGuid(validUser.getGuid());
        userRecordInsert.setUserId(validUser.getUserId());
        userRecordInsert.setUserJobNumber(validUser.getUserJobNumber());
        userRecordInsert.setPhone(validUser.getPhone());
        userRechargeRecordMapper.insert(userRecordInsert);
        //生成流水
        UserTransaction userTransaction = new UserTransaction();
        BeanUtil.copyProperties(userRecordInsert, userTransaction);
        userTransaction.setTransactionNumber(userRecordInsert.getRechargeNumber());
        userTransaction.setAccountType(rechargePhoneDTO.getRechargeType());
        userTransaction.setTransactionType("6");
        userTransaction.setTransactionTime(LocalDateTime.now());
        userTransaction.setCashAccount(user.getCashAccount());
        userTransaction.setCardAccount(user.getCardAccount());
        userTransaction.setRechargeStream(rechargeStream);
        userTransaction.setTradeType(1);
        userTransaction.setUserId(validUser.getUserId());
        userTransaction.setUserJobNumber(validUser.getUserJobNumber());
        userTransaction.setPhone(validUser.getPhone());
        userTransaction.setUserMealsNumber(user.getUserMealsNumber());
        userTransactionMapper.insert(userTransaction);
        return Boolean.TRUE;
    }

    @Override
    public ReadExcelVO read(MultipartFile multipartFile) {
        ReadExcelVO readExcelVO = new ReadExcelVO();
        ReadExcelVO readExcelVOError = new ReadExcelVO();
        List<String> errorList = new ArrayList<>();

        List<RechargeBatchExcelVO> dataList = new ArrayList<>();
        try {
            EasyExcel.read(multipartFile.getInputStream(), RechargeBatchExcelVO.class, new AnalysisEventListener<RechargeBatchExcelVO>() {
                @Override
                public void invoke(RechargeBatchExcelVO rechargeBatchDTO, AnalysisContext analysisContext) {
                    dataList.add(rechargeBatchDTO);
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                    log.info("所有数据解析完成,记录数: {}", dataList.size());
                }
            }).sheet().doRead();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("读取到的数据 >>> {}", dataList);

        if (dataList.isEmpty()) {
            errorList.add("文件不能为空");
            readExcelVOError.setErrorList(errorList);
            return readExcelVOError;
        }

        if (dataList.size() > 5000) {
            errorList.add("充值批量数量不能超过5000条");
            readExcelVOError.setErrorList(errorList);
            return readExcelVOError;
        }

        List<RechargeBatchDTO> rechargeBatchDTOList = new ArrayList<>();

        int index = 2;
        for (RechargeBatchExcelVO rechargeBatchExcelVO : dataList) {
            RechargeBatchDTO rechargeBatchDTO = new RechargeBatchDTO();
            BeanUtil.copyProperties(rechargeBatchExcelVO, rechargeBatchDTO);
            if (rechargeBatchExcelVO == null) {
                continue;
            }

            if (StrUtil.isBlank(rechargeBatchExcelVO.getGuid())) {
                errorList.add("第" + index + "行第" + 1 + "列中guid为空");
            }

            if (StrUtil.isBlank(rechargeBatchExcelVO.getRechargeNumberString())) {
                errorList.add("第" + index + "行第" + 6 + "列中充值金额为空");
            } else {
                //标记是否为数字
                boolean flag = false;
                String number = rechargeBatchDTO.getRechargeNumberString().replaceFirst("\\.", "");
                for (int v = 0; v < number.length(); v++) {
                    if (!Character.isDigit(number.charAt(v))) {
                        //表示不是数字
                        flag = true;
                        errorList.add("第" + index + "行第" + 6 + "列中充值金额为非纯数字");
                    }
                }
                //如果为纯数字  判断大于0小于10000
                if (!flag) {
                    if (Double.parseDouble(rechargeBatchExcelVO.getRechargeNumberString()) <= 0) {
                        errorList.add("第" + index + "行第" + 6 + "列中充值金额不能小于等于0");
                    } else if (Double.parseDouble(rechargeBatchExcelVO.getRechargeNumberString()) >= 10000) {
                        errorList.add("第" + index + "行第" + 6 + "列中充值金额不能大于10000");
                    } else {
                        rechargeBatchDTO.setRechargeNumber(new BigDecimal(rechargeBatchExcelVO.getRechargeNumberString()));
                    }
                }
            }

            if (StrUtil.isBlank(rechargeBatchExcelVO.getRechargeType())) {
                errorList.add("第" + index + "行第" + 7 + "列中充值类型为空");
            }

            if (StrUtil.isNotBlank(rechargeBatchExcelVO.getNotes())) {
                if (rechargeBatchExcelVO.getNotes().length() > 20) {
                    errorList.add("第" + index + "行第" + 8 + "列中备注最多20个字符");
                }
            }
            rechargeBatchDTOList.add(rechargeBatchDTO);
            index++;
        }

        if (!errorList.isEmpty()) {
            readExcelVO.setErrorList(errorList);
        }
        if (errorList.isEmpty()) {
            readExcelVO.setRechargeBatchDTOList(rechargeBatchDTOList);

            String originalFilename = multipartFile.getOriginalFilename();
            assert originalFilename != null;

            String fileName = new String(originalFilename.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            Date date = new Date();
            try {
                String bucketName = minioUtil.getBucketName();
                String oldPath = minioUtil.uploadFile(bucketName, multipartFile.getInputStream(), "scs/download" + date.getTime()
                        , fileName, false);
                readExcelVO.setFileOldPath(oldPath);
                String subStringFileName = fileName.substring(0, fileName.lastIndexOf("."));
                readExcelVO.setFileName(subStringFileName);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        return readExcelVO;
    }

    public static int doubleLength(double number) {
        // 将double转换为字符串
        String numberStr = Double.toString(number);
        // 判断负数的情况
        if (numberStr.startsWith("-")) {
            numberStr = numberStr.substring(1);
        }
        // 判断是否包含小数点
        if (numberStr.contains(".")) {
            numberStr = numberStr.split("\\.")[0];
        }
        // 返回长度
        return numberStr.length();
    }


    @Override
    public boolean rechargeBatch(RechargeBatchJsonDTO rechargeBatchJsonList) {
        //转为list实体类
        List<RechargeBatchDTO> rechargeBatchList = JsonToListUtil.getJsonToList(rechargeBatchJsonList.getRechargeBatchJsonList());

        //首先对数据进行去空格处理
        //批量充值成功的
        List<RechargeBatchDTO> rechargeBatchSuccessList = new ArrayList<>();
        //批量充值失败的
        List<RechargeBatchDTO> rechargeBatchFailList = new ArrayList<>();
        //发送充值流水list
        List<UserRechargeRecord> userRechargeRecordList = new ArrayList<>();
        //交易流水list
        List<UserTransaction> userTransactionList = new ArrayList<>();


        for (RechargeBatchDTO rechargeBatchDTO : rechargeBatchList) {

            if (rechargeBatchDTO == null) {
                continue;
            }

            //批量充值加redis锁
            RLock lock = redissonClient.getLock("getAccountLock" + rechargeBatchDTO.getGuid());


            try {
                // 直接获取锁，阻塞式
                lock.lock(10, TimeUnit.SECONDS);

                if (rechargeBatchDTO.getRechargeNumber().scale() > 2) {
                    //小数点后超过2位
                    rechargeBatchDTO.setRechargeStatus("充值失败");
                    rechargeBatchDTO.setRechargeFail("小数点后超过2位");
                    rechargeBatchFailList.add(rechargeBatchDTO);
                } else if (rechargeBatchDTO.getRechargeNumber().compareTo(BigDecimal.ZERO) < 0 || rechargeBatchDTO.getRechargeNumber().compareTo(new BigDecimal(10000)) > 0) {
                    //金额大于10000
                    rechargeBatchDTO.setRechargeStatus("充值失败");
                    rechargeBatchDTO.setRechargeFail("充值金额应小于10000,大于0");
                    rechargeBatchFailList.add(rechargeBatchDTO);
                } else if (!rechargeBatchDTO.getRechargeType().equals("现金账户") && !rechargeBatchDTO.getRechargeType().equals("餐补账户")) {
                    //类型错误
                    rechargeBatchDTO.setRechargeStatus("充值失败");
                    rechargeBatchDTO.setRechargeFail("充值类型错误,现目前仅支持现金账户或餐补账户");
                    rechargeBatchFailList.add(rechargeBatchDTO);
                } else if (StrUtil.isNotBlank(rechargeBatchDTO.getNotes()) && rechargeBatchDTO.getNotes().length() > 20) {
                    //备注不能超过20个字符
                    rechargeBatchDTO.setRechargeStatus("充值失败");
                    rechargeBatchDTO.setRechargeFail("备注不能超过20个字符");
                    rechargeBatchFailList.add(rechargeBatchDTO);
                } else {

                    SysUser user = sysUserMapper.selectByGuid(rechargeBatchDTO.getGuid());
                    if (user == null) {
                        rechargeBatchDTO.setRechargeStatus("充值失败");
                        rechargeBatchDTO.setRechargeFail("账户不存在");
                        rechargeBatchFailList.add(rechargeBatchDTO);
                    } else if (user.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                        //充值失败
                        rechargeBatchDTO.setRechargeStatus("充值失败");
                        rechargeBatchDTO.setRechargeFail("账户已冻结");
                        rechargeBatchFailList.add(rechargeBatchDTO);
                    } else if (rechargeBatchDTO.getRechargeType().equals(RechargeTypeEnum.MEAL_ACCOUNT.getDesc())) {
                        //餐补
                        if (user.getCardState().equals("2")) {
                            //充值失败
                            rechargeBatchDTO.setRechargeStatus("充值失败");
                            rechargeBatchDTO.setRechargeFail("餐补账户已冻结");
                            rechargeBatchFailList.add(rechargeBatchDTO);
                        } else {
                            //充值成功
                            //发送流水 回滚金额
                            rechargeBatch(userRechargeRecordList, userTransactionList, rechargeBatchDTO, user, rechargeBatchSuccessList);
                        }

                    } else if (rechargeBatchDTO.getRechargeType().equals(RechargeTypeEnum.CASH_ACCOUNT.getDesc())) {
                        //现金账户
                        if (user.getCashState().equals("2")) {
                            //充值失败
                            rechargeBatchDTO.setRechargeStatus("充值失败");
                            rechargeBatchDTO.setRechargeFail("现金账户已冻结");
                            rechargeBatchFailList.add(rechargeBatchDTO);
                        } else {
                            rechargeBatch(userRechargeRecordList, userTransactionList, rechargeBatchDTO, user, rechargeBatchSuccessList);
                        }
                    }
                }

            } finally {
                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
        if (!userTransactionList.isEmpty()) {
            log.info("交易流水:{}", JSON.toJSONString(userTransactionList));
            userTransactionService.saveBatch(userTransactionList);
        }
        //批量生成充值流水和交易流水
        if (!userRechargeRecordList.isEmpty()) {
            log.info("充值流水:{}", JSON.toJSONString(userRechargeRecordList));
            userRechargeRecordService.saveBatch(userRechargeRecordList);
        }

        //处理导出存入oss中并返回path
        // 成功的
        UserHistoryRecharge userHistoryRecharge = new UserHistoryRecharge();
        String successPath = listToExcel(new AtomicInteger(1), 1, "充值成功数据", rechargeBatchSuccessList, "充值成功信息");
        String failPath = listToExcel(new AtomicInteger(1), 2, "充值失败数据", rechargeBatchFailList, "充值失败信息");
        //存入表中
        userHistoryRecharge.setRechargeTime(LocalDateTime.now());
        userHistoryRecharge.setCreateTime(LocalDateTime.now());
        userHistoryRecharge.setRechargeFile(rechargeBatchJsonList.getFileOldPath());
        userHistoryRecharge.setRechargeFileName(rechargeBatchJsonList.getFileName());
        userHistoryRecharge.setRechargeSuccessFile(successPath);
        userHistoryRecharge.setRechargeFailFile(failPath);
        userHistoryRechargeMapper.insert(userHistoryRecharge);

        return Boolean.TRUE;
    }

    /**
     * excel 导出文件公共方法
     *
     * @param type      1为成功  2为失败
     * @param sheetName 页名称
     * @param list      list数据
     * @param fileName  文件名称
     * @return 文件访问路径
     */
    private String listToExcel(AtomicInteger index, Integer type, String sheetName, List<RechargeBatchDTO> list, String fileName) {
        //封装表头
        List<UserRechargeBatchSuccessVO> successList = new ArrayList<>();
        List<UserRechargeBatchFailVO> failList = new ArrayList<>();
        for (RechargeBatchDTO rechargeBatchDTO : list) {
            //填充数据
            UserRechargeBatchFailVO userRechargeBatchFailVO = new UserRechargeBatchFailVO();
            UserRechargeBatchSuccessVO userRechargeBatchSuccessVO = new UserRechargeBatchSuccessVO();
            BeanUtil.copyProperties(rechargeBatchDTO, userRechargeBatchFailVO);
            BeanUtil.copyProperties(rechargeBatchDTO, userRechargeBatchSuccessVO);
            SysUser sysUser = sysUserMapper.selectByGuid(rechargeBatchDTO.getGuid());
            if (sysUser != null) {
                if (StrUtil.isNotBlank(sysUser.getUsername())) {
                    userRechargeBatchFailVO.setUsername(sysUser.getUsername());
                    userRechargeBatchSuccessVO.setUsername(sysUser.getUsername());
                }
                if (StrUtil.isNotBlank(sysUser.getUserJobNumber())) {
                    userRechargeBatchFailVO.setUserJobNumber(sysUser.getUserJobNumber());
                    userRechargeBatchSuccessVO.setUserJobNumber(sysUser.getUserJobNumber());
                }
                if (StrUtil.isNotBlank(sysUser.getPhone())) {
                    userRechargeBatchFailVO.setPhone(sysUser.getPhone());
                    userRechargeBatchSuccessVO.setPhone(sysUser.getPhone());
                }
                if (sysUser.getUserType() != null) {
                    userRechargeBatchFailVO.setUserTypeName(UserTypeToNameUtil.getUserType(sysUser.getUserType()));
                    userRechargeBatchSuccessVO.setUserTypeName(UserTypeToNameUtil.getUserType(sysUser.getUserType()));
                }
            }
            if (type == 1) {
                userRechargeBatchSuccessVO.setIndex(index.getAndIncrement());
                successList.add(userRechargeBatchSuccessVO);
            }
            if (type == 2) {
                userRechargeBatchFailVO.setIndex(index.getAndIncrement());
                failList.add(userRechargeBatchFailVO);
            }
        }
        Workbook workbook = null;
        //生成excel文档
        if (type == 1) {
            workbook = ExcelExportUtil.exportExcel(new ExportParams("充值成功信息", sheetName), UserRechargeBatchSuccessVO.class, successList);
        } else {
            workbook = ExcelExportUtil.exportExcel(new ExportParams("充值失败信息", sheetName), UserRechargeBatchFailVO.class, failList);
        }
        Date date = new Date();
        //存入oss中  返回地址
        String bucketName = minioUtil.getBucketName();
        return minioUtil.uploadFile(bucketName, UserTypeToNameUtil.getExcelInputSteam(workbook), "scs/download" + date.getTime(), fileName + XLSX, false);
    }

    private void rechargeBatch(List<UserRechargeRecord> userRechargeRecordList, List<UserTransaction> userTransactionList, RechargeBatchDTO batchDTO, SysUser user, List<RechargeBatchDTO> rechargeBatchSuccessList) {
        //充值成功  生产充值流水
        String rechargeStream = UserTypeToNameUtil.setRechargeStream();
        UserRechargeRecord userRechargeRecord = new UserRechargeRecord();
        BeanUtil.copyProperties(user, userRechargeRecord);
        userRechargeRecord.setLastRechargeTime(LocalDateTime.now());
        userRechargeRecord.setCreateBy(user.getUsername());
        userRechargeRecord.setRechargeStream(rechargeStream);
        userRechargeRecord.setRechargeChannel(RechargeChannelEnum.BACK_GROUND.getCode());
        userRechargeRecord.setRechargeType(batchDTO.getRechargeType().equals(RechargeTypeEnum.MEAL_ACCOUNT.getDesc()) ? RechargeTypeEnum.MEAL_ACCOUNT.getCode() : RechargeTypeEnum.CASH_ACCOUNT.getCode());
        userRechargeRecord.setUserType(user.getUserType());
        userRechargeRecord.setNotes(batchDTO.getNotes());
        userRechargeRecord.setRechargeNumber(batchDTO.getRechargeNumber());
        userRechargeRecord.setGuid(user.getGuid());
        if (userRechargeRecord.getRechargeType().equals("1")) {
            userRechargeRecord.setCardAccount(user.getCardAccount().add(batchDTO.getRechargeNumber()));
            userRechargeRecord.setCashAccount(user.getCashAccount());
        }
        if (userRechargeRecord.getRechargeType().equals("2")) {
            userRechargeRecord.setCashAccount(user.getCashAccount().add(batchDTO.getRechargeNumber()));
            userRechargeRecord.setCardAccount(user.getCardAccount());
        }
        userRechargeRecordList.add(userRechargeRecord);
        //交易流水
        UserTransaction userTransaction = new UserTransaction();
        BeanUtil.copyProperties(user, userTransaction);
        userTransaction.setTransactionNumber(userRechargeRecord.getRechargeNumber());
        userTransaction.setAccountType(userRechargeRecord.getRechargeType());
        userTransaction.setTransactionType("6");
        userTransaction.setTransactionTime(LocalDateTime.now());
        userTransaction.setRechargeStream(rechargeStream);
        userTransaction.setNotes(batchDTO.getNotes());

        if (userRechargeRecord.getRechargeType().equals("1")) {
            userTransaction.setCardAccount(user.getCardAccount().add(batchDTO.getRechargeNumber()));
            userTransaction.setCashAccount(user.getCashAccount());
            sysUserMapper.incrByCardAccount(user.getGuid(), batchDTO.getRechargeNumber(), LocalDateTime.now());
        }
        if (userRechargeRecord.getRechargeType().equals("2")) {
            userTransaction.setCashAccount(user.getCashAccount().add(batchDTO.getRechargeNumber()));
            userTransaction.setCardAccount(user.getCardAccount());
            sysUserMapper.incrByCashAccount(user.getGuid(), batchDTO.getRechargeNumber(), LocalDateTime.now());
        }
        userTransaction.setTradeType(1);
        userTransactionList.add(userTransaction);

        batchDTO.setRechargeStatus("充值成功");
        rechargeBatchSuccessList.add(batchDTO);
    }

    @Override
    public boolean getIdFile(MultipartFile multipartFile, Long historyId, String fileName) {
        //前端返回的filename解码
        String name = URLDecoder.decode(fileName, StandardCharsets.UTF_8);
        UserHistoryRecharge userHistoryRecharge = new UserHistoryRecharge();
        Date date = new Date();
        try {
            String bucketName = minioUtil.getBucketName();
            String oldPath = minioUtil.uploadFile(bucketName, multipartFile.getInputStream(), "scs/download" + date.getTime()
                    , name, false);
            userHistoryRecharge.setRechargeFile(oldPath);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        userHistoryRecharge.setHistoryId(historyId);
        userHistoryRecharge.setRechargeFileName(name);
        userHistoryRechargeMapper.updateById(userHistoryRecharge);
        return Boolean.TRUE;
    }

    @Override
    public IPage getUserRecordPage(Page page, RechargePageDTO rechargePageDTO) {
        Page<UserRechargeRecord> userRechargeRecordPage = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<UserRechargeRecord> queryWrapper = getUserRechargeRecordLambdaQueryWrapper(rechargePageDTO, 2);
        return userRechargeRecordMapper.selectPage(userRechargeRecordPage, queryWrapper);
    }

    private static @NotNull LambdaQueryWrapper<UserRechargeRecord> getUserRechargeRecordLambdaQueryWrapper(RechargePageDTO rechargePageDTO, Integer isExcel) {
        if (StrUtil.isBlank(rechargePageDTO.getBeginTime()) && StrUtil.isBlank(rechargePageDTO.getEndTime())
                && rechargePageDTO.getUserId() == null && StrUtil.isBlank(rechargePageDTO.getUserJobNumber())
                && StrUtil.isBlank(rechargePageDTO.getRechargeChannel()) && StrUtil.isBlank(rechargePageDTO.getRechargeType())
                && StrUtil.isBlank(rechargePageDTO.getGuid())
                && StrUtil.isBlank(rechargePageDTO.getPhone()) && StrUtil.isBlank(rechargePageDTO.getOrderId())
                && StrUtil.isBlank(rechargePageDTO.getOutOrderNo())) {
            rechargePageDTO.setBeginTime(LocalDate.now().plusDays(-3).toString());
        }
        LambdaQueryWrapper<UserRechargeRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(rechargePageDTO.getUserId() != null, UserRechargeRecord::getUserId, rechargePageDTO.getUserId())
                .eq(StrUtil.isNotBlank(rechargePageDTO.getUserJobNumber()), UserRechargeRecord::getUserJobNumber, rechargePageDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(rechargePageDTO.getPhone()), UserRechargeRecord::getPhone, rechargePageDTO.getPhone())
                .eq(StrUtil.isNotBlank(rechargePageDTO.getOutOrderNo()), UserRechargeRecord::getOutOrderNo, rechargePageDTO.getOutOrderNo())
                .eq(StrUtil.isNotBlank(rechargePageDTO.getOrderId()), UserRechargeRecord::getOrderId, rechargePageDTO.getOrderId())
                .eq(StrUtil.isNotBlank(rechargePageDTO.getGuid()), UserRechargeRecord::getGuid, rechargePageDTO.getGuid())
                .eq(StrUtil.isNotBlank(rechargePageDTO.getRechargeChannel()), UserRechargeRecord::getRechargeChannel, rechargePageDTO.getRechargeChannel())
                .eq(StrUtil.isNotBlank(rechargePageDTO.getRechargeType()), UserRechargeRecord::getRechargeType, rechargePageDTO.getRechargeType())
                .eq(UserRechargeRecord::getDelFlag, "0")
                .ge(StrUtil.isNotBlank(rechargePageDTO.getBeginTime()), UserRechargeRecord::getCreateTime, UserTypeToNameUtil.stringToLocalBeginTime(rechargePageDTO.getBeginTime()))
                .le(StrUtil.isNotBlank(rechargePageDTO.getEndTime()), UserRechargeRecord::getCreateTime, UserTypeToNameUtil.stringToLocalEndTime(rechargePageDTO.getEndTime()))
                .orderByDesc(UserRechargeRecord::getCreateTime, UserRechargeRecord::getRechargeRecordId);

        if (isExcel == 1) {
            queryWrapper.last(" limit 100000");
        }
        return queryWrapper;
    }

    @Override
    public List<UserHistoryExcelVO> getUserRecordExport(RechargePageDTO rechargePageDTO) {
        LambdaQueryWrapper<UserRechargeRecord> queryWrapper = getUserRechargeRecordLambdaQueryWrapper(rechargePageDTO,1);
        List<UserRechargeRecord> userRechargeRecordList = userRechargeRecordMapper.selectList(queryWrapper);
        List<UserHistoryExcelVO> userExcelList = new ArrayList<>();
        AtomicInteger index = new AtomicInteger(1);

        List<SysUser> sysUserList = sysUserMapper.selectList(null);
        userRechargeRecordList.forEach(a -> {
            UserHistoryExcelVO userHistoryExcelVO = new UserHistoryExcelVO();
            BeanUtil.copyProperties(a, userHistoryExcelVO);
            if (a.getUserId() != null) {
                SysUser sysUser = sysUserList.stream().filter(Objects::nonNull)
                        .filter(cc -> a.getUserId().equals(cc.getUserId()))
                        .findFirst().orElse(null);

                if (sysUser != null && sysUser.getUserType() != null) {
                    userHistoryExcelVO.setUserTypeName(UserTypeToNameUtil.getUserType(sysUser.getUserType()));
                }

                userHistoryExcelVO.setIndex(index.getAndIncrement());
                if (!a.getRechargeType().isEmpty()) {
                    userHistoryExcelVO.setRechargeType(a.getRechargeType().equals(RechargeTypeEnum.MEAL_ACCOUNT.getCode()) ? RechargeTypeEnum.MEAL_ACCOUNT.getDesc() : RechargeTypeEnum.CASH_ACCOUNT.getDesc());
                }
                if (a.getRechargeChannel() != null) {
                    switch (a.getRechargeChannel()) {
                        case "1":
                            userHistoryExcelVO.setRechargeChannel(RechargeChannelEnum.MAN_KE_BAO.getDesc());
                            break;
                        case "2":
                            userHistoryExcelVO.setRechargeChannel(RechargeChannelEnum.JIN_DONG.getDesc());
                            break;
                        case "3":
                            userHistoryExcelVO.setRechargeChannel(RechargeChannelEnum.SHANG_CHAO.getDesc());
                            break;
                        case "4":
                            userHistoryExcelVO.setRechargeChannel(RechargeChannelEnum.BACK_GROUND.getDesc());
                            break;
                    }
                }
                userExcelList.add(userHistoryExcelVO);
            }

        });
        return userExcelList;
    }

    @Override
    public String getExcel() {
        return userDictMapper.selectById(1).getDictValue();
    }

}
